package cn.stylefeng.guns.aspect;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.request.async.WebAsyncUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.Objects;

@Aspect
@Component
@Order(Integer.MIN_VALUE-2)
@Slf4j
public class RestLogAspect {

    @Autowired
    ObjectMapper objectMapper;

    /**
     * @org.springframework.web.bind.annotation.RestController *
     * +
     *             "&&!@annotation(org.springframework.amqp.rabbit.annotation.RabbitListener)"
     *+
     *             "&&!@annotation(NoAspectLog)"
     *                 @Pointcut("execution(public * com.example.demo.controller..*.*(..))")
     */
    @Pointcut("execution(public * cn.stylefeng.guns.modular.controller..*.*(..))")
    public void webLog() {

    }

    /**
     * @param joinPoint 切入点
     */
    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) {
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes == null) {
                log.info("unable to get the request from RequestContextHolder,please check the rest api{}", joinPoint.getSignature());
                return;
            }

            HttpServletRequest request = attributes.getRequest();
            //Whether a result value exists as a result of concurrent handling.
            if (WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() || null == request) {
                log.info("unable to get the request from RequestContextHolder,please check the rest api{}", joinPoint.getSignature());
            } else {
                String params = objectMapper.writeValueAsString(request.getParameterMap());
                //接收到请求，记录请求内容
                log.info(" >>> receive request, " +
                                "url:{}, " +
                                "queryString: {}, " +
                                " method:{}," +
                                " params: {} ",
                        request.getRequestURI(),
                        request.getQueryString(),
                        request.getMethod(),
                        params);

                log.info(" >>> Payload : {}", objectMapper.writeValueAsString(filterJoinPointArgs(joinPoint)));
            }
        } catch (Exception e) {
            log.error(" webLog aspect error: ", e);
        }
    }


    /**
     * doAfterReturning 异步打印日志
     *
     * @param joinPoint 切入点
     * @param rvt
     */
    //@AfterReturning(value = "webLog()||within(@AspectLogTarget *)", returning = "rvt")
//    public void doAfterReturning(JoinPoint joinPoint, Object rvt) {
//        // 处理完请求，返回内容
//        try {
//            //如果是GlobalExceptionHandler直接Error打印
//            if(joinPoint.getTarget() instanceof GlobalExceptionHandler){
//                log.error(">>> calling " + joinPoint.getSignature() + " responsne:{}",
//                        SimplifyResponseLog.reduceLog(objectMapper.writeValueAsString(rvt)));
//                return;
//            }
//            if (log.isInfoEnabled()) {
//                log.info(">>> calling " + joinPoint.getSignature() + " responsne:{}",
//                        SimplifyResponseLog.reduceLog(objectMapper.writeValueAsString(rvt)));
//            } else if (log.isWarnEnabled()) {
//                log.warn(">>> calling " + joinPoint.getSignature() + " responsne:{}",
//                        SimplifyResponseLog.reduceLog(objectMapper.writeValueAsString(rvt)));
//            }
//        } catch (JsonProcessingException e) {
//            log.error("doAfterReturning error{}", e.getMessage());
//        }
//    }


    /**
     * 过滤joinPoint,eg:doRequest(HttpServletResponse httpServletResponse,HttpServletResponse request),过滤掉response参数
     *
     * @param joinPoint
     */
    private final Object[] filterJoinPointArgs(JoinPoint joinPoint) {

        if (ObjectUtils.isEmpty(joinPoint.getArgs())) {
            return joinPoint.getArgs();
        }
        //过滤掉参数中的request和Response
        return Arrays.asList(joinPoint.getArgs()).stream().filter(Objects::nonNull)
                .filter(item -> !(item instanceof HttpServletResponse)
                        && !(item instanceof HttpServletRequest) && !(item instanceof BindingResult)).toArray();


    }

}